﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;

namespace Core.LockStep
{
    public interface IInterpolationData : IStreamData
    {
        void InterpolationEnd();
    }

    public abstract class InterpolationData<ValueType, DataType> : StepData<DataType>, IInterpolationData
    {
        public ValueType Last { get; protected set; }
        public ValueType Current { get; protected set; }

        public void SetValue(ValueType value)
        {
            Last = value;
            Current = value;
        }

        public void SwapValue(ValueType value)
        {
            Last = Current;
            Current = value;
        }

        public void InterpolationEnd()
        {
            Last = Current;
        }

        public override void Clear()
        {
            Last = default;
            Current = default;
        }

        public abstract ValueType Interpolation { get; }
    }

    public class Vector3IntData : InterpolationData<Vector3Int, Vector3IntData>
    {
        public override Vector3IntData ReadFrom(IFrameDataStream stream)
        {
            Last = stream.ReadV3I();
            Current = stream.ReadV3I();
            return this;
        }

        public override void WriteTo(IFrameDataStream stream)
        {
            stream.WriteV3I(Last);
            stream.WriteV3I(Current);
        }

        public override Vector3Int Interpolation
        {
            get
            {
                var x = Mathf.Lerp(Last.x, Current.x, LockStepTool.Interpolation);
                var y = Mathf.Lerp(Last.y, Current.y, LockStepTool.Interpolation);
                var z = Mathf.Lerp(Last.z, Current.z, LockStepTool.Interpolation);

                return new Vector3Int((int)x, (int)y, (int)z);
            }
        }
    }

    public class Vector2IntData : InterpolationData<Vector2Int, Vector2IntData>
    {
        public override Vector2IntData ReadFrom(IFrameDataStream stream)
        {
            Last = stream.ReadV2I();
            Current = stream.ReadV2I();
            return this;
        }

        public override void WriteTo(IFrameDataStream stream)
        {
            stream.WriteV2I(Last);
            stream.WriteV2I(Current);
        }

        public override Vector2Int Interpolation
        {
            get
            {
                var x = Mathf.Lerp(Last.x, Current.x, LockStepTool.Interpolation);
                var y = Mathf.Lerp(Last.y, Current.y, LockStepTool.Interpolation);

                return new Vector2Int((int)x, (int)y);
            }
        }
    }

    public class IntData : InterpolationData<int, IntData>
    {
        public override IntData ReadFrom(IFrameDataStream stream)
        {
            Last = stream.ReadInt32();
            Current = stream.ReadInt32();
            return this;
        }

        public override void WriteTo(IFrameDataStream stream)
        {
            stream.WriteInt32(Last);
            stream.WriteInt32(Current);
        }

        public override int Interpolation
        {
            get
            {
                return (int)Mathf.Lerp(Last, Current, LockStepTool.Interpolation);
            }
        }
    }
}